package org.app.appjson.adapter;

import org.app.appjson.exception.AppJsonException;
import org.app.appjson.reader.JsonLexer;
import org.app.appjson.reader.JsonToken;
import org.app.appjson.reader.ReadHandler;
import org.app.appjson.writer.WriteHandler;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 数组类型适配器
 * @param <E> 泛型参数
 * @author lizhongsi
 * @version 1.0
 * @since 1.0
 */
public final class ArrayAdapter<E> implements TypeAdapter {

    public static <E> Object read(ReadHandler handler) throws AppJsonException {
        JsonLexer lexer = handler.getLexer();
        if (lexer.peek().getType() == JsonToken.NULL) {
            lexer.next();
            return null;
        }
        if (lexer.peek().getType() != JsonToken.BEGIN_ARRAY) {// 必须以'['开始
            throw new AppJsonException("Array must start with '['.");
        }
        lexer.next(); //消费'['
        List<E> list = new ArrayList<>(); //创建集合对象
        Class<?> classOfElement = handler.getObjectClass(null); //保存集合中每一个元素的类型
        while (lexer.peek().getType() != JsonToken.END_ARRAY) {
            E element = (E) handler.doRead(classOfElement); //根据元素类型创建元素对象
            list.add(element);
            if (lexer.peek().getType() == JsonToken.SEP_COMMA) {// 消费两个元素之间的分隔符','
                lexer.next();
            }
        }
        if (lexer.peek().getType() != JsonToken.END_ARRAY) { //必须以']'结尾
            throw new AppJsonException("Array must end with ']'.");
        }
        lexer.next(); //消费']'字符
        int size = list.size();
        Object array = Array.newInstance(classOfElement, size);
        for (int i = 0; i < size; i++) {
            Array.set(array, i, list.get(i));
        }
        return array;
    }

    public static <E> void write(WriteHandler handler) throws AppJsonException {
        Object object = handler.getObject();
        if (!(object.getClass().isArray())) { //非数组抛出异常
            throw new AppJsonException("Object is not an array.");
        }
        Object[] array = asObjectArray(object);
        ArrayList<E> list = new ArrayList<>((List<E>) Arrays.asList(array));
        boolean isArrayEmpty = true;
        handler.write("[");
        for (E element : list) {
            if (!isArrayEmpty) {//数组不空则拼一个','
                handler.write(",");
            }
            handler.doWrite(element);
            isArrayEmpty = false;
        }
        handler.write("]");
    }

    public static Object[] asObjectArray(Object array) {
        int length = Array.getLength(array);
        Object[] objectArray = new Object[length];
        for (int i = 0; i < length; i++) {
            objectArray[i] = Array.get(array, i);
        }
        return objectArray;
    }
}
